﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace SuperX.Helper.Validation
{
    public class ValidationMain
    {
        /// <summary>
        /// 检查对象属性是否有效
        /// </summary>
        /// <param name="obj"></param>
        public static void ScanIsValid(object obj, Options options = Options.Properties)
        {
            Type type = obj.GetType();
            switch (options)
            {
                case Options.Properties:
                    CheckProperty(obj, type.GetProperties());
                    break;
                case Options.Fields:
                    CheckField(obj, type.GetFields());
                    break;
                case Options.All:
                    CheckProperty(obj, type.GetProperties());
                    CheckField(obj, type.GetFields());
                    break;
                default:
                    break;
            }

        }

        /// <summary>
        /// 检查属性
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="properties"></param>
        private static void CheckProperty(object obj, PropertyInfo[] properties)
        {
            // 对每个属性进行检查，是否符合要求
            foreach (PropertyInfo property in properties)
            {
                var attrs = property.GetCustomAttributes(true);
                if (attrs != null)
                {
                    // 开始对属性进行特性验证
                    foreach (Attribute attr in attrs)
                    {
                        if (!IsValidationAttribute(attr)) continue;
                        object value = property.GetValue(obj, null);
                        MethodInfo attrMethod = attr.GetType().GetMethod("IsValid", new Type[] { typeof(object) });
                        InvokeMethod(attrMethod, attr, value, property.Name);
                    }
                }
            }
        }

        /// <summary>
        /// 检查字段
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="properties"></param>
        private static void CheckField(object obj, FieldInfo[] properties)
        {
            // 对每个属性进行检查，是否符合要求
            foreach (FieldInfo fieldInfo in properties)
            {
                var attrs = fieldInfo.GetCustomAttributes(true);
                if (attrs != null)
                {
                    // 开始对属性进行特性验证
                    foreach (Attribute attr in attrs)
                    {
                        if (!IsValidationAttribute(attr)) continue;
                        object value = fieldInfo.GetValue(obj);
                        MethodInfo attrMethod = attr.GetType().GetMethod("IsValid", new Type[] { typeof(object) });
                        InvokeMethod(attrMethod, attr, value, fieldInfo.Name);
                    }
                }
            }
        }

        /// <summary>
        /// 执行方法
        /// </summary>
        /// <param name="attrMethod"></param>
        /// <param name="attr"></param>
        /// <param name="value"></param>
        /// <param name="Name"></param>
        /// <exception cref="Exception"></exception>
        public static void InvokeMethod(MethodInfo attrMethod, Attribute attr, object value, string Name)
        {
            try
            {
                attrMethod.Invoke(attr, new object[] { value });
            }
            catch (TargetInvocationException ex)//内部报错会被Invoke捕捉
            {
                if (ex.InnerException != null)
                {
                    throw new Exception(message: $"{Name}:{ex.InnerException.Message}");//重新抛出
                }
            }
        }

        /// <summary>
        /// 检查多个对象属性是否有效
        /// </summary>
        /// <param name="objs"></param>
        public static void ScanIsValid(object[] objs)
        {
            foreach (var item in objs)
            {
                ScanIsValid(item);
            }
        }

        /// <summary>
        /// 判断是否是自定义的特性
        /// </summary>
        /// <param name="attribute"></param>
        /// <returns></returns>
        private static bool IsValidationAttribute(Attribute attribute)
        {
            Type type = attribute.GetType();
            return type.BaseType == typeof(ValidationAttribute);
        }
    }

    public enum Options
    {
        Properties,
        Fields,
        All
    }
}
